package com.my.chapter14;

import java.util.*;

public class practice12 {
    public static void main(String[] args) {
        TypeCounter counter = new TypeCounter(Coffee.class);
        for(Iterator<Coffee> it =
            new CoffeeGenerator(20).iterator(); it.hasNext();) {
            Coffee coffee = it.next();
            System.out.print(coffee.getClass().getSimpleName() + " ");
            counter.count(coffee);
        }
        System.out.println("");
        System.out.println(counter);
    }
}

class TypeCounter extends HashMap<Class<?>,Integer>{
    private Class<?> baseType;
    public TypeCounter(Class<?> baseType){
        this.baseType = baseType;
    }
    public void count(Object obj){
        Class<?> type = obj.getClass();
        if(!baseType.isAssignableFrom(type))
            throw new RuntimeException(obj + " incorrect type：" + type + ",should be type or subtype of " + baseType);
        countClass(type);
    }
    private void countClass(Class<?> type){
        Integer quantity = get(type);
        put(type,quantity==null ? 1:quantity+1);
        Class<?> superClass = type.getSuperclass();
        if(superClass !=null && baseType.isAssignableFrom(superClass))
            countClass(superClass);
    }

    @Override
    public String toString() {
        StringBuilder result = new StringBuilder();
        for(Map.Entry<Class<?>,Integer> pair:entrySet()){
            result.append(pair.getKey().getSimpleName());
            result.append("=");
            result.append(pair.getValue());
            result.append(", ");
        }
        result.delete(result.length()-2,result.length());
        result.append("}");
        return result.toString();
    }
}

class Coffee{
    private static long counter = 0;
    private final long id = counter++;

    @Override
    public String toString() {
        return getClass().getSimpleName() + " " + id;
    }
}

class Latte extends Coffee{}

class Mocha extends Coffee{}

class Cappuccino extends Coffee{}

class Americano extends Coffee{}

class Breve extends Coffee{}

class CoffeeGenerator implements Iterable<Coffee>{
    private Class[] types = {Latte.class,Mocha.class,Cappuccino.class,
            Americano.class,Breve.class};
    private static Random rand = new Random(47);
    public CoffeeGenerator(){}
    private int size=0;
    public CoffeeGenerator(int sz){
        size = sz;
    }

    public Coffee next(){
        try{
            return (Coffee) types[rand.nextInt(types.length)].newInstance();
        }catch (Exception e){
            throw new RuntimeException(e);
        }
    }

    class CoffeeIterator implements Iterator<Coffee>{
        int count  = size;

        @Override
        public boolean hasNext() {
            return count>0;
        }

        @Override
        public Coffee next() {
            count--;
            return CoffeeGenerator.this.next();
        }

        @Override
        public void remove() {
            throw new UnsupportedOperationException();
        }
    }

    @Override
    public Iterator<Coffee> iterator() {
        return new CoffeeIterator();
    }
}



